﻿/*
 * @author: wizardc
 */

using System;
using System.Collections.Generic;
using UnityEngine;

namespace Demo.WorldMap.Prefab
{
    /// <summary>
    /// 预制资源加载及缓存类
    /// </summary>
    public class PrefabResCache
    {
        /// <summary>
        /// 资源加载完毕时回调
        /// </summary>
        public event Action<int, GameObject> onLoadComplete;
        
        private PrefabStaticRenderRes[] _res;
        
        private HashSet<int> _assetLoadingSet = new HashSet<int>();
        private Dictionary<int, GameObject> _assetMap = new Dictionary<int, GameObject>();
        private Dictionary<int, string> _assetNameMap = new Dictionary<int, string>();
        private Dictionary<int, Stack<GameObject>> _resMap = new Dictionary<int, Stack<GameObject>>();

        private int _maxCacheNum = 5;
        private bool _isDestroy = false;
        
        public PrefabResCache(PrefabStaticRenderRes[] res)
        {
            _res = res;
        }

        /// <summary>
        /// 最多缓存实例数量
        /// </summary>
        public int maxCacheNum
        {
            get => _maxCacheNum;
            set => _maxCacheNum = value;
        }

        /// <summary>
        /// 取一个资源实例
        /// </summary>
        public bool GetRes(int resId, out GameObject gameObject)
        {
            if (_resMap.ContainsKey(resId) && _resMap[resId].Count > 0)
            {
                var go = _resMap[resId].Pop();
                go.SetActive(true);
                gameObject = go;
                return true;
            }
            if (_assetMap.ContainsKey(resId))
            {
                var asset = _assetMap[resId];
                gameObject = GameObject.Instantiate(asset);
                return true;
            }
            if (!_assetLoadingSet.Contains(resId))
            {
                _assetLoadingSet.Add(resId);
                var resName = _res[resId].prefabName;
                WorldMapAssetUtil.LoadObject(resName, (path, obj) =>
                {
                    if (_isDestroy)
                    {
                        WorldMapAssetUtil.ReleaseObject(resName);
                        return;
                    }
                    
                    var asset = (GameObject) obj;
                    _assetMap.Add(resId, asset);
                    _assetNameMap.Add(resId, resName);
                    _assetLoadingSet.Remove(resId);
                    onLoadComplete?.Invoke(resId, asset);
                });
            }
            gameObject = null;
            return false;
        }

        /// <summary>
        /// 回收一个资源实例
        /// </summary>
        public void RecycleRes(int resId, GameObject gameObject)
        {
            if (!_resMap.ContainsKey(resId))
            {
                _resMap.Add(resId, new Stack<GameObject>());
            }
            var pool = _resMap[resId];
            if (pool.Count >= _maxCacheNum)
            {
                GameObject.Destroy(gameObject);
            }
            else
            {
                gameObject.SetActive(false);
                pool.Push(gameObject);
            }
        }

        /// <summary>
        /// 销毁
        /// </summary>
        public void Dispose()
        {
            _isDestroy = true;
            _assetLoadingSet.Clear();
            foreach (var kv in _assetNameMap)
            {
                WorldMapAssetUtil.ReleaseObject(kv.Value);
            }
            _assetNameMap.Clear();
            _assetMap.Clear();
            foreach (var kv in _resMap)
            {
                foreach (var gameObject in kv.Value)
                {
                    GameObject.Destroy(gameObject);
                }
            }
            _resMap.Clear();
        }
    }
}
